﻿using System;
using System.Collections.Generic;
using System.Reflection;
using XNode;

/// <summary>
/// 此类的子类中的Output和Input字段应声明为public
/// 目前会忽略DynamicPortList，不要中途修改DynamicPortList的值
/// </summary>
public class MyXNode : Node
{
    protected List<FieldInfo> inputs = new List<FieldInfo>();
    protected List<FieldInfo> listInputs = new List<FieldInfo>();

    protected override void Init()
    {
        base.Init();
        FieldInfo[] fields = GetType().GetFields();
        foreach (FieldInfo field in fields)
        {
            InputAttribute inputAttribute = field.GetAttribute<InputAttribute>();
            if (inputAttribute != null && !inputAttribute.dynamicPortList)
            {
                if (typeof(Array).IsAssignableFrom(field.FieldType))
                    listInputs.Add(field);
                else
                    inputs.Add(field);
            }
        }
    }

    /// <summary>
    /// 自动让字段接收来自连线的输入，一般情况不需要重写
    /// </summary>
    public virtual void Input()
    {
        foreach (FieldInfo field in inputs)
        {
            field.SetValue(this, GetInputValue(field.FieldType, field.Name));
        }
        foreach (FieldInfo field in listInputs)
        {
            field.SetValue(this, GetInputValues(field.FieldType, field.Name));
        }
    }

    /// <summary>
    /// 产生连线上的输出，需要重写
    /// </summary>
    public virtual object Output(NodePort port)
    {
        return null;
    }

    public override object GetValue(NodePort port)
    {
        return Output(port);
    }
    public override void OnCreateConnection(NodePort from, NodePort to)
    {
        Input();
    }
    public override void OnRemoveConnection(NodePort port)
    {
        Input();
    }

    //插件提供的API只有泛型方法，没有以类型为参数的方法
    public object GetInputValue(Type type, string fieldName)
    {
        MethodInfo method = typeof(Node).GetMethod(nameof(GetInputValue)).MakeGenericMethod(type);
        object ret = method.Invoke(this, new object[] { fieldName, null });
        return ret;
    }

    public object GetInputValues(Type arrayType, string fieldName)
    {
        MethodInfo method = typeof(Node).GetMethod(nameof(GetInputValues)).MakeGenericMethod(arrayType.GetElementType());
        object ret = method.Invoke(this, new object[] { fieldName, null });
        return ret;
    }
}